#define SCDLL
#include "SpellCore.Interop.h"
#undef SCDLL

#import "..\..\output\Debug\SpellCore.tlb"
#import "..\..\output\Debug\SpellCore.Connector.tlb" rename_namespace("SpellCore")

SCAPIDECL HSCCHECKER SCAPI CreateSpellChecker(LPCWSTR szWritingSystemId){
  if(szWritingSystemId == NULL || szWritingSystemId[0] == L'\0'){
    return NULL;
  }

  HRESULT hr = CoInitialize(NULL);
  if(FAILED(hr)){
    return NULL;
  }

  try{
    SpellCore::ISpellCheckerRegistryPtr iSpellCheckerRegistry(__uuidof(SpellCore::SpellCheckerRegistry));
    SpellCore::ISpellCheckerPtr iSpellChecker = iSpellCheckerRegistry->Item[szWritingSystemId];
    return iSpellChecker.Detach();
  }
  catch(_com_error err){
  }
  return NULL;
}

SCAPIDECL void SCAPI FreeSpellChecker(HSCCHECKER pChecker){
  if(pChecker == NULL){
    return;
  }

  try{
    SpellCore::ISpellCheckerPtr iSpellChecker((SpellCore::ISpellChecker*) pChecker, false/*we want to take ownership*/);
  }
  catch(_com_error err){
  }
  CoUninitialize();
}

SCAPIDECL BOOL SCAPI CanCheckSpelling(HSCCHECKER checker){
  BOOL fCanCheckSpelling = false;
  try{
    SpellCore::ISpellCheckerPtr iSpellChecker((SpellCore::ISpellChecker*) checker, true/*we don't want to take ownership*/);
    fCanCheckSpelling = iSpellChecker->HasEngines != false; // true is -1 but we'd rather it be 1 
  }
  catch(_com_error err){
  }
  return fCanCheckSpelling;
}

SCAPIDECL void SCAPI AddGoodWord(HSCCHECKER checker, LPCWSTR strWord, UINT cchSize){
  if(strWord == NULL || cchSize == 0){
    return;
  }
  BSTR bstrWord = ::SysAllocStringLen(strWord, cchSize);
  if(bstrWord != NULL){
    try{
      SpellCore::ISpellCheckerPtr iSpellChecker((SpellCore::ISpellChecker*) checker, true/*we don't want to take ownership*/);
		  iSpellChecker->AddGoodWord(bstrWord);
    }
    catch(_com_error err){
    }
    ::SysFreeString(bstrWord);
  }
}

SCAPIDECL enum CheckingResult SCAPI GetWordStatus(HSCCHECKER checker, LPCWSTR strWord, UINT cchSize){
  enum CheckingResult checkingResult = CheckingResultUnknown;
  if(strWord == NULL || cchSize == 0){
    return checkingResult;
  }

  BSTR bstrWord = ::SysAllocStringLen(strWord, cchSize);
  if(bstrWord != NULL){
    try{
      SpellCore::ISpellCheckerPtr iSpellChecker((SpellCore::ISpellChecker*) checker, true/*we don't want to take ownership*/);
      checkingResult = (CheckingResult) iSpellChecker->GetWordStatus(bstrWord);
    }
    catch(_com_error err){
    }
    ::SysFreeString(bstrWord);
  }
  return checkingResult;
}

SCAPIDECL HSCSUGGESTIONLIST SCAPI GetSuggestions(HSCCHECKER checker, LPCWSTR strWord, UINT cchSize){
	BSTR bstrWord = ::SysAllocStringLen(strWord, cchSize);
  if(bstrWord != NULL){
    try{
      SpellCore::ISpellCheckerPtr iSpellChecker((SpellCore::ISpellChecker*) checker, true/*we don't want to take ownership*/);
      IEnumVARIANTPtr iEnumSuggestions = iSpellChecker->InteropGetSuggestions(bstrWord);
      ::SysFreeString(bstrWord);
      return iEnumSuggestions.Detach();
    }
    catch(_com_error err){
      ::SysFreeString(bstrWord);
    }
  }
  return NULL;
}

SCAPIDECL void SCAPI FreeSuggestions(HSCSUGGESTIONLIST hSuggestions){
  if(hSuggestions == NULL){
    return;
  }

  try{
    IEnumVARIANTPtr iEnumSuggestions((IEnumVARIANT*) hSuggestions, false/*we want to take ownership*/);
  }
  catch(_com_error err){
  }
}

// Score is optional
SCAPIDECL BOOL SCAPI GetNextSuggestion(HSCSUGGESTIONLIST hSuggestionList, LPWSTR szSuggestionBuffer, UINT cchBuffer, long* pScore){
  if(szSuggestionBuffer == NULL || cchBuffer == 0){
    return false;
  }
  try{
    IEnumVARIANTPtr iEnumSuggestions((IEnumVARIANT*) hSuggestionList, true/*we don't want to take ownership*/);
    HRESULT hr;
    do {
      VARIANT v;
      hr = iEnumSuggestions->Next(1, &v, NULL);
      if(hr == S_OK){
        SpellCore::ISimilarityCheckResultPtr iSimilarityCheckResult(v);
        if(iSimilarityCheckResult != NULL){
          _bstr_t word = iSimilarityCheckResult->word;
          if(word.length() < cchBuffer){
            if(pScore != NULL) {
              *pScore = iSimilarityCheckResult->SimilarityScore;
            }
  #pragma warning(suppress:4996)
            wcsncpy(szSuggestionBuffer,word, word.length()+1);
            return true;
          }
          else { //skip it, it's too long
            continue;
          }
        }
      }
    }
    while(hr == S_OK);
  }
  catch(_com_error err){
  }
  return false;
}

